/*
 * $Id:
 *
 * Copyright (C) 2011 Refiner Inc.
 * All right reserved
 *
 *============================================================
 * +rVPN Stack : HelperIF (VPN Helper Interface)
 *============================================================
 * abstract: Functions for VPN Helper
 * author  : MURATA
 * history :
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <time.h>
#include <sys/time.h>
#include <unistd.h>
#include <ctype.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "rvs_msg.h"
#include "rvs_appif.h"
#include "rvs_socket.h"
#include "rvs_helpif.h"

#define	RCVBUFLEN	2048

/* ステータスとエラーをチェックする */
int  rvs_status_check(rvs_status_t* statusp, rvs_error_t* errorp)
{
    rvs_api_send_t* smsg = NULL;
    rvs_api_msg_t rmsg;
    char rcvbuf[RCVBUFLEN];
    int ns, seqno;
    int status = -1;

    LOGD("%s: Enter\n", __FUNCTION__);

    memset (&rmsg, 0, sizeof(rmsg));

    /* 送信用ソケットの確保 */
    ns = rvs_api_new();
    if (ns < 0) {
        LOGE("%s: cannot get spi_sock\n", __FUNCTION__);
        status = RVS_STAT_NONE;   /* 2012.1.23 EM */
        goto statexit;
    }

    /* 送信メッセージの作成 */
    smsg = rvs_make_msg(RAPI_M_STATUSCHECK, -1, 0);
    if (smsg == NULL) {
        LOGE("%s: rvs_make_msg failed.\n", __FUNCTION__);
        goto sockerr;
    }

    /* パラメータの設定 */
    /*    入力パラメータはなし */

    /* シーケンス番号の保存 */
    seqno = smsg->header.seqno;

    /* メッセージの送信 */
    if (rvs_send_msg (rvs_api_sock(ns), smsg) < 0) {
        goto sockerr;
    }

    /* 応答の受信 */
    if (rvs_recv_msg (rvs_api_sock(ns), &rmsg, RAPI_M_STATUSCHECK_RES, seqno,
                rcvbuf, RCVBUFLEN, NULL, NULL) == NULL) {
        goto sockerr;
    }

    /* 戻り値 */
    status = rmsg.header->status;
    if (rmsg.header->status < 0) {
        if (rmsg.rerr) {
            rvs_set_errno(rmsg.rerr->Integer);
        }
    } else {
        if (rmsg.statinfo == NULL) {
            rvs_set_errno(EINVAL);
            status = -1;
        } else {
            /* ユーザ名リスト領域は静的領域で用意 */
            static const char* remotelist[MAX_P2PCON];
            static char remotes[MAX_P2PCON][USERNAMELEN+1];
            rvs_api_str_t* uidp;
            int i;
            /* ステータス情報を読み込む */
            status = 0;
            statusp->vpnstat = rmsg.statinfo->VPNStat;
            statusp->p2pcon = rmsg.statinfo->P2PCount;
            if (statusp->p2pcon > MAX_P2PCON) {
                statusp->p2pcon = MAX_P2PCON;
            }
            memset (remotes, 0, sizeof(remotes));
            uidp = rmsg.statinfo->Remote;
            for (i=0; i<statusp->p2pcon; i++) {
                int len = uidp->Length;
                strncpy (remotes[i], uidp->String,
                               (len>USERNAMELEN)?USERNAMELEN:len);
                remotelist[i] = remotes[i];
                if (len % sizeof(uint32_t)) {
                    len += (sizeof(uint32_t) - len%sizeof(uint32_t));
                }
                uidp = (rvs_api_str_t*)&uidp->String[len];
            }
            statusp->remotename = remotelist;

            /* エラーコードを設定する */
            if (rmsg.errinfo == NULL) {
                memset (errorp, 0, sizeof(rvs_error_t));
            } else {
                errorp->rtype = rmsg.errinfo->RequestType;
                errorp->reason_type = rmsg.errinfo->ReasonType;
                if (errorp->reason_type == RVS_REASON_2) {
                    errorp->reason.reason2[0] = rmsg.errinfo->ErrCode.RCode2[0];
                    errorp->reason.reason2[1] = rmsg.errinfo->ErrCode.RCode2[1];
                } else {
                    errorp->reason.reason3[0] = rmsg.errinfo->ErrCode.RCode3[0];
                    errorp->reason.reason3[1] = rmsg.errinfo->ErrCode.RCode3[1];
                    errorp->reason.reason3[2] = rmsg.errinfo->ErrCode.RCode3[2];
                }
                errorp->remote = NULL;
                if (rmsg.errinfo->Length >
                            (sizeof(rvs_api_error_t)+sizeof(uint32_t))) {
                    int len = rmsg.errinfo->Remote[0].Length;
                    if (len > 0) {
                        static char connname[USERNAMELEN+1];
                        if (len > USERNAMELEN) {
                            len = USERNAMELEN;
                        }
                        strncpy (connname, rmsg.errinfo->Remote[0].String, len);
                        connname[len] = 0;
                        errorp->remote = connname;
                    }
                }
            }
        }
    }

sockerr:
    rvs_api_free(ns);
    if (smsg) {
        rvs_free(smsg);
    }
    rvs_free_msg(&rmsg);

statexit:
    LOGD("%s: Retun(%d)\n", __FUNCTION__, status);
    return status;
}
